// Package collector
// 职责范围: 采集业务逻辑（参数验证、执行操作、解析结果）
// 不负责的工作: 配置处理、客户端配置细节、协议转换逻辑
package collector

import (
	"context"
	"errors"
	"fmt"
	"log/slog"
	"net"
	"time"
	"unicode/utf8"

	"dcs/config"
	"dcs/scraper"
	"github.com/gosnmp/gosnmp"
)

// SNMPRequest 采集请求结构
type SNMPRequest struct {
	Target    string                 `json:"target"`
	Operation string                 `json:"operation"`
	OIDs      []string               `json:"oids"`
	ConfigRaw map[string]interface{} `json:"config"` // 原始配置
}

// SNMPResult 采集结果结构
type SNMPResult struct {
	Success   bool       `json:"success"`
	Target    string     `json:"target"`
	Operation string     `json:"operation"`
	Duration  float64    `json:"duration"`
	Data      []SNMPData `json:"data"`
	Error     string     `json:"error"`
}

// SNMPData 单条数据
type SNMPData struct {
	OID   string `json:"oid"`
	Type  string `json:"type"`
	Value string `json:"value"`
}

// Collector 采集器
type Collector struct {
	logger *slog.Logger
}

func NewCollector(logger *slog.Logger) *Collector {
	return &Collector{
		logger: logger.With("component", "collector"),
	}
}

// Collect 执行采集
func (c *Collector) Collect(req SNMPRequest) (*SNMPResult, error) {
	startTime := time.Now()
	result := &SNMPResult{
		Target:    req.Target,
		Operation: req.Operation,
		Success:   false,
	}

	if err := c.validateBusinessParams(req); err != nil {
		result.Error = err.Error()
		return result, err
	}

	snmpCfg, err := config.NewSNMPConfig(req.ConfigRaw)
	if err != nil {
		result.Error = fmt.Sprintf("invalid config: %v", err)
		return result, err
	}

	client, err := c.createSNMPClient(req.Target, snmpCfg)
	if err != nil {
		result.Error = fmt.Sprintf("client init failed: %v", err)
		return result, err
	}
	defer client.Close()

	pdus, err := c.executeOperation(client, req)
	if err != nil {
		result.Error = err.Error()
		return result, err
	}

	result.Data = c.parsePDUs(pdus)
	result.Success = true
	result.Duration = time.Since(startTime).Seconds()
	return result, nil
}

// 验证业务参数
func (c *Collector) validateBusinessParams(req SNMPRequest) error {
	if req.Target == "" {
		return errors.New("target is required")
	}
	if len(req.OIDs) == 0 {
		return errors.New("oids cannot be empty")
	}
	if req.Operation != "get" && req.Operation != "walk" {
		return errors.New("operation must be 'get' or 'walk'")
	}
	uniqueOIDs := make(map[string]struct{})
	for _, oid := range req.OIDs {
		if oid == "" {
			return errors.New("oid cannot be empty")
		}
		uniqueOIDs[oid] = struct{}{}
	}
	return nil
}

// 创建SNMP客户端
func (c *Collector) createSNMPClient(target string, cfg *config.SNMPConfig) (scraper.SNMPScraper, error) {
	client, err := scraper.NewGoSNMP(
		c.logger,
		target,
		cfg.SourceAddress,
		c.logger.Enabled(context.Background(), slog.LevelDebug),
	)
	if err != nil {
		return nil, err
	}

	client.SetOptions(cfg.ToGoSNMPOptions()...)

	if err := client.Connect(); err != nil {
		client.Close()
		return nil, err
	}
	return client, nil
}

// 执行采集操作
func (c *Collector) executeOperation(client scraper.SNMPScraper, req SNMPRequest) ([]gosnmp.SnmpPDU, error) {
	switch req.Operation {
	case "get":
		packet, err := client.Get(req.OIDs)
		if err != nil {
			return nil, fmt.Errorf("get failed: %w", err)
		}
		return packet.Variables, nil
	case "walk":
		var allPDUs []gosnmp.SnmpPDU
		for _, oid := range req.OIDs {
			walkPDUs, err := client.WalkAll(oid)
			if err != nil {
				c.logger.Warn("walk oid failed", "oid", oid, "error", err)
				continue
			}
			allPDUs = append(allPDUs, walkPDUs...)
		}
		return allPDUs, nil
	default:
		return nil, errors.New("unsupported operation")
	}
}

// 解析PDU列表
func (c *Collector) parsePDUs(pdus []gosnmp.SnmpPDU) []SNMPData {
	var dataList []SNMPData
	for _, pdu := range pdus {
		if pdu.Type == gosnmp.NoSuchObject || pdu.Type == gosnmp.NoSuchInstance {
			continue
		}
		dataList = append(dataList, SNMPData{
			OID:   pdu.Name,
			Type:  c.getTypeName(pdu.Type),
			Value: c.parseValue(pdu),
		})
	}
	return dataList
}

// 获取数据类型名称（修复：确保所有分支返回）
func (c *Collector) getTypeName(t gosnmp.Asn1BER) string {
	switch t {
	case gosnmp.Integer:
		return "Integer"
	case gosnmp.OctetString:
		return "String"
	case gosnmp.IPAddress:
		return "IPAddress"
	case gosnmp.Counter32:
		return "Counter32"
	case gosnmp.Gauge32:
		return "Gauge32"
	case gosnmp.TimeTicks:
		return "TimeTicks"
	case gosnmp.Counter64:
		return "Counter64"
	case gosnmp.Uinteger32:
		return "UInteger32"
	case gosnmp.ObjectIdentifier:
		return "OID"
	case gosnmp.Opaque:
		return "Opaque"
	default:
		return fmt.Sprintf("Unknown(%d)", t) // 确保default分支有返回
	}
}

// 解析PDU值（修复：确保所有分支返回）
func (c *Collector) parseValue(pdu gosnmp.SnmpPDU) string {
	switch pdu.Type {
	case gosnmp.Integer, gosnmp.Counter32, gosnmp.Gauge32, gosnmp.Counter64, gosnmp.Uinteger32:
		return fmt.Sprintf("%d", gosnmp.ToBigInt(pdu.Value))
	case gosnmp.OctetString:
		// 优先解析为 UTF-8 字符串，非字符串字节数组显示为十六进制
		switch v := pdu.Value.(type) {
		case string:
			return v // 已为字符串直接返回
		case []byte:
			if utf8.Valid(v) {
				return string(v) // 有效 UTF-8 转换为字符串
			}
			return fmt.Sprintf("binary (0x% X)", v) // 非字符串字节数组
		default:
			return fmt.Sprintf("unknown (%v)", v)
		}
	case gosnmp.IPAddress:
		if ip, ok := pdu.Value.(net.IP); ok {
			return ip.String()
		}
		return fmt.Sprintf("IPAddress(%v)", pdu.Value)
	case gosnmp.ObjectIdentifier:
		if oid, ok := pdu.Value.(string); ok {
			return oid
		}
		return fmt.Sprintf("OID(%v)", pdu.Value)
	case gosnmp.TimeTicks:
		ticks := gosnmp.ToBigInt(pdu.Value).Uint64()
		return fmt.Sprintf("%ds", ticks/100)
	case gosnmp.Opaque:
		if bytes, ok := pdu.Value.([]byte); ok {
			return fmt.Sprintf("Opaque(0x%X)", bytes)
		}
		return fmt.Sprintf("Opaque(%v)", pdu.Value)
	default:
		// 补充：默认分支返回值，确保所有情况都有返回
		return fmt.Sprintf("%v", pdu.Value)
	}
}
